#!/usr/bin/env python3
"""
Prometheus告警分析模块
支持DeepSeek AI分析和内置分析
"""

import requests
import logging
from typing import List, Dict, Any, Tuple
from config import Config
from utils import LogUtils

logger = logging.getLogger(__name__)

class PrometheusAlertAnalyzer:
    """Prometheus告警分析器 - 支持AI和内置分析"""
    
    def __init__(self):
        self.api_config = Config.get_api_config()
        self.ai_engine = self.api_config.get('ai_engine', 'deepseek')
        self.enable_ai = self.api_config.get('enable_ai_analysis', True)
        
        # AI服务配置
        self.deepseek_config = self.api_config.get('deepseek', {})
        self.ollama_config = self.api_config.get('ollama', {})
        
        # 严重程度映射
        self.severity_map = {
            'info': "信息",
            'warning': "警告", 
            'critical': "严重",
            'emergency': "紧急"
        }
    
    def analyze_alerts(self, alerts: List[Dict[str, Any]]) -> Tuple[str, bool]:
        """
        分析告警 - 自动选择分析方式
        返回: (分析结果, AI是否成功)
        """
        if not alerts:
            return "✅ **Prometheus系统状态正常**\n\n当前没有活跃的告警，所有监控目标运行正常。", True
        
        total_alerts = len(alerts)
        
        # 告警风暴检测和处理
        if total_alerts > 30:
            logger.warning(f"检测到告警风暴：{total_alerts} 个告警")
            return self._handle_alert_storm(alerts)
        
        # 正常告警数量（2-30条）
        if total_alerts >= 2:
            # 如果启用AI分析且配置了AI服务，使用AI分析
            if self.enable_ai:
                if self.ai_engine == 'deepseek' and self.deepseek_config.get('enabled'):
                    logger.info(f"告警数量适中，使用DeepSeek AI进行聚合分析")
                    return self._deepseek_analysis(alerts)
                elif self.ai_engine == 'ollama' and self.ollama_config.get('enabled'):
                    logger.info(f"告警数量适中，使用Ollama进行分析")
                    return self._ollama_analysis(alerts)
                else:
                    logger.info(f"选择的AI引擎 {self.ai_engine} 未启用或未配置，使用内置分析")
                    return self._builtin_analysis(alerts), True
            else:
                logger.info("AI分析已禁用，使用内置分析")
                return self._builtin_analysis(alerts), True
        
        # 单个告警直接使用内置分析
        logger.info("单个告警，使用内置分析")
        return self._builtin_analysis(alerts), True
    
    def _deepseek_analysis(self, alerts: List[Dict[str, Any]]) -> Tuple[str, bool]:
        """使用DeepSeek API分析告警"""
        alert_summary = self._build_alert_summary(alerts)
        
        # 打印发送给DeepSeek的原始数据
        LogUtils.log_raw_data_sent("DeepSeek", alert_summary)
        
        prompt = f"""
作为资深运维专家，请对以下Prometheus告警进行简洁尖锐的初步诊断：

{alert_summary}

请提供**简洁实用**的初步诊断报告，要求：

**输出格式要求**：
- 使用 **粗体** 强调重要内容
- 使用简单的 - 列表格式
- 禁止使用markdown标题符号(##、###等)
- 禁止使用代码块和技术命令
- 章节间用空行分隔

**分析内容**：
1. **问题概述**：一句话概括当前告警的核心问题和影响范围
2. **故障分析**：简要分析每类告警的可能原因和相互关联
3. **影响评估**：评估对业务系统的潜在影响
4. **处理优先级**：按紧急程度排列处理顺序
5. **初步建议**：提供针对性的处理思路和方向

请保持分析的专业性和实用性，重点关注问题的本质和关联性。输出要简洁、直接、不冗余。
"""
        
        try:
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.deepseek_config.get('api_key')}"
            }
            
            payload = {
                "model": self.deepseek_config.get('model', 'deepseek-chat'),
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.7,
                "max_tokens": 1500
            }
            
            response = requests.post(
                self.deepseek_config.get('api_url'),
                headers=headers,
                json=payload,
                timeout=self.deepseek_config.get('timeout', 60)
            )
            
            if response.status_code == 200:
                result = response.json()
                ai_analysis = result['choices'][0]['message']['content']
                
                # 使用简洁文本格式
                formatted_analysis = f"{ai_analysis}\n\n---\n💡 *以上分析由AI运维助手提供，仅供参考*"
                
                LogUtils.log_ai_analysis_result('DeepSeek', True)
                
                # 根据AI分析输入数据透明化要求，打印完整数据
                print("\n" + "="*80)
                print("📤 发送给DeepSeek的完整数据:")
                print("\n[聚合服务告警数据]")
                print(alert_summary)
                print("\n[DeepSeek AI分析结果]")
                print(ai_analysis)
                print("="*80 + "\n")
                
                return formatted_analysis, True
            else:
                LogUtils.log_ai_analysis_result('DeepSeek', False)
                return self._builtin_analysis(alerts), False
                
        except Exception as e:
            LogUtils.log_ai_analysis_result('DeepSeek', False)
            logger.error(f"DeepSeek API调用异常: {e}")
            return self._builtin_analysis(alerts), False
    
    def _ollama_analysis(self, alerts: List[Dict[str, Any]]) -> Tuple[str, bool]:
        """使用Ollama进行本地AI分析"""
        alert_summary = self._build_alert_summary(alerts)
        
        # 打印发送给Ollama的原始数据
        LogUtils.log_raw_data_sent("Ollama", alert_summary)
        
        try:
            payload = {
                "model": self.ollama_config.get('model', 'llama3.1:8b'),
                "prompt": f"请分析以下Prometheus告警并提供处理建议：\n\n{alert_summary}",
                "stream": False
            }
            
            response = requests.post(
                f"{self.ollama_config.get('base_url')}/api/generate",
                json=payload,
                timeout=self.ollama_config.get('timeout', 120)
            )
            
            if response.status_code == 200:
                result = response.json()
                ai_analysis = result.get('response', '分析失败')
                
                formatted_analysis = f"🤖 **本地AI分析**\n\n{ai_analysis}\n\n---\n💡 *以上分析由本地AI助手提供，仅供参考*"
                
                LogUtils.log_ai_analysis_result('Ollama', True)
                
                # 根据AI分析输入数据透明化要求，打印完整数据
                print("\n" + "="*80)
                print("📤 发送给Ollama的完整数据:")
                print("\n[聚合服务告警数据]")
                print(alert_summary)
                print("\n[Ollama AI分析结果]")
                print(ai_analysis)
                print("="*80 + "\n")
                
                return formatted_analysis, True
            else:
                LogUtils.log_ai_analysis_result('Ollama', False)
                return self._builtin_analysis(alerts), False
                
        except Exception as e:
            LogUtils.log_ai_analysis_result('Ollama', False)
            logger.error(f"Ollama API调用异常: {e}")
            return self._builtin_analysis(alerts), False
    
    def _build_alert_summary(self, alerts: List[Dict[str, Any]]) -> str:
        """构建告警摘要 - 优化服务聚合和数据结构"""
        total_alerts = len(alerts)
        severity_count = {}
        services_affected = set()
        
        # 按类型聚合告警
        alert_categories = self._categorize_alerts(alerts)
        
        # 按服务聚合告警原因
        service_issues = {}
        
        for alert in alerts:
            severity = alert.get('severity', 'warning')
            severity_count[severity] = severity_count.get(severity, 0) + 1
            
            # 提取服务名
            instance = alert.get('instance', '未知实例')
            service_name = self._extract_service_name(instance)
            services_affected.add(service_name)
            
            # 聚合服务问题
            alert_name = alert.get('alert_name', '未知告警')
            summary = alert.get('summary', alert.get('description', ''))
            
            if service_name not in service_issues:
                service_issues[service_name] = {
                    'alert_name': alert_name,
                    'summary': summary,
                    'count': 0,
                    'severity': severity
                }
            service_issues[service_name]['count'] += 1
        
        # 构建聚合后的告警摘要
        summary = f"Prometheus告警聚合分析：\n"
        summary += f"总告警数：{total_alerts} 个，影响服务：{len(services_affected)} 个\n\n"
        
        # 服务问题聚合汇总（新增）
        summary += "🔴 **服务问题汇总**\n"
        for service_name, issue_info in sorted(service_issues.items()):
            count = issue_info['count']
            alert_name = issue_info['alert_name']
            issue_summary = issue_info['summary']
            severity = issue_info['severity']
            
            summary += f"• {service_name}: {count} 个 {alert_name} ({severity})\n"
            if issue_summary:
                summary += f"  原因: {issue_summary}\n"
        
        summary += "\n"
        
        # 告警类型聚合汇总
        summary += "🔍 **告警类型汇总**\n"
        for category, items in alert_categories.items():
            services_info = self._get_instances_info(items)
            summary += f"{len(items)} 个 {category}：{services_info}\n"
        
        summary += "\n"
        
        # 严重程度统计
        summary += "📈 **严重程度分布**\n"
        
        # 先检查是否有严重程度数据
        if severity_count:
            for severity in ['emergency', 'critical', 'warning', 'info']:
                if severity in severity_count:
                    count = severity_count[severity]
                    severity_name = self.severity_map.get(severity, severity)
                    percentage = round(count / total_alerts * 100)
                    summary += f"• {severity_name}: {count} 个 ({percentage}%)\n"
        else:
            # 如果没有严重程度数据，显示默认信息
            summary += f"• 警告: {total_alerts} 个 (100%)\n"
        
        # 根据DeepSeek分析输入格式规范，添加处理建议部分
        summary += "\n🔧 **处理建议**\n"
        summary += "• 请根据以上服务问题提供具体的技术分析和处理方案\n"
        
        return summary
    
    def _categorize_alerts(self, alerts: List[Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]:
        """按类型对告警进行分类"""
        categories = {}
        
        for alert in alerts:
            category = self._classify_alert_type(alert)
            
            if category not in categories:
                categories[category] = []
            categories[category].append(alert)
        
        # 按告警数量排序
        return dict(sorted(categories.items(), key=lambda x: len(x[1]), reverse=True))
    
    def _classify_alert_type(self, alert: Dict[str, Any]) -> str:
        """根据告警名称和标签分类告警类型"""
        alert_name = alert.get('alert_name', '').lower()
        labels = alert.get('labels', {})
        
        # JVM相关告警
        if any(keyword in alert_name for keyword in ['fullgc', 'gc', 'jvm', 'heap', 'outofmemory']):
            return "🟡 JVM性能告警"
        
        # 实例不可达
        if any(keyword in alert_name for keyword in ['instancedown', 'nodedown', 'targetdown']):
            return "🔴 实例不可达"
        
        # CPU相关
        if any(keyword in alert_name for keyword in ['cpu', 'load', 'processor']):
            return "📈 CPU负载告警"
        
        # 内存相关
        if any(keyword in alert_name for keyword in ['memory', 'mem', 'ram', 'oom']):
            return "💾 内存告警"
        
        # 磁盘相关  
        if any(keyword in alert_name for keyword in ['disk', 'filesystem', 'storage', 'space']):
            return "💽 磁盘空间告警"
        
        # 网络相关
        if any(keyword in alert_name for keyword in ['network', 'connection', 'timeout']):
            return "🌐 网络连接告警"
        
        # 服务相关
        if any(keyword in alert_name for keyword in ['service', 'process', 'container', 'pod']):
            return "⚙️ 服务状态告警"
        
        # 数据库相关
        if any(keyword in alert_name for keyword in ['mysql', 'postgresql', 'redis', 'mongo']):
            return "🗄️ 数据库告警"
        
        return "❓ 其他告警"
    
    def _get_instances_info(self, alerts: List[Dict[str, Any]]) -> str:
        """获取实例信息，智能显示服务名或数量"""
        services = set()
        for alert in alerts:
            instance = alert.get('instance', '未知实例')
            # 简化实例名显示 - 将Pod名称转换为服务名
            service_name = self._extract_service_name(instance)
            services.add(service_name)
        
        if len(services) <= 3:
            return f"({', '.join(sorted(services))})"
        else:
            return f"({len(services)} 个服务)"
    
    def _extract_service_name(self, instance: str) -> str:
        """从 Pod 实例名提取服务名"""
        if ':' in instance:
            instance = instance.split(':')[0]
        
        # 处理 Kubernetes Pod 命名模式: service-name-hash-podid
        # 例如: bos-server-7ff9f5b4c4-vw5lc -> bos-server
        #      gts-quote-7c99b66465-zjrr6 -> gts-quote
        parts = instance.split('-')
        if len(parts) >= 3:
            # 去掉最后两个部分（hash 和 podid）
            service_parts = parts[:-2]
            return '-'.join(service_parts)
        else:
            # 如果不符合模式，返回原始名称
            return instance
    
    def _handle_alert_storm(self, alerts: List[Dict[str, Any]]) -> Tuple[str, bool]:
        """处理告警风暴情况"""
        total_alerts = len(alerts)
        
        # 过滤高价值告警
        filtered_alerts = self._filter_high_value_alerts(alerts)
        filtered_count = len(filtered_alerts)
        
        logger.info(f"告警风暴过滤：从 {total_alerts} 个告警中筛选出 {filtered_count} 个高价值告警")
        
        # 生成风暴报告
        storm_report = self._generate_storm_report(alerts, filtered_alerts)
        
        return storm_report, False
    
    def _filter_high_value_alerts(self, alerts: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """过滤出高价值告警"""
        high_value_alerts = []
        
        for alert in alerts:
            if self._is_high_value_alert(alert):
                high_value_alerts.append(alert)
        
        # 按严重程度排序，只取前15个最重要的
        high_value_alerts.sort(key=lambda x: self._get_alert_priority_score(x), reverse=True)
        return high_value_alerts[:15]
    
    def _is_high_value_alert(self, alert: Dict[str, Any]) -> bool:
        """判断是否为高价值告警"""
        alert_name = alert.get('alert_name', '').lower()
        severity = alert.get('severity', 'warning')
        
        # 严重和紧急级别告警
        if severity in ['critical', 'emergency']:
            return True
        
        # 实例不可达
        if any(keyword in alert_name for keyword in ['down', 'unreachable', 'failed']):
            return True
        
        # 排除测试和临时告警
        if any(keyword in alert_name for keyword in ['test', 'demo', 'tmp']):
            return False
        
        return True
    
    def _get_alert_priority_score(self, alert: Dict[str, Any]) -> int:
        """计算告警优先级分数"""
        score = 0
        
        severity = alert.get('severity', 'warning')
        if severity == 'emergency':
            score += 100
        elif severity == 'critical':
            score += 80
        elif severity == 'warning':
            score += 40
        
        alert_name = alert.get('alert_name', '').lower()
        if 'down' in alert_name:
            score += 30
        elif 'high' in alert_name:
            score += 20
        
        return score
    
    def _generate_storm_report(self, all_alerts: List[Dict[str, Any]], filtered_alerts: List[Dict[str, Any]]) -> str:
        """生成告警风暴报告"""
        total_count = len(all_alerts)
        filtered_count = len(filtered_alerts)
        
        report = f"🌪️ **告警风暴检测**\n\n"
        report += f"系统检测到大量告警：**{total_count}** 个活跃告警\n"
        report += f"经过智能过滤，筛选出 **{filtered_count}** 个高价值告警\n\n"
        
        if filtered_alerts:
            alert_categories = self._categorize_alerts(filtered_alerts)
            report += "🔥 **重点关注告警类型**\n"
            for category, items in list(alert_categories.items())[:5]:
                report += f"• {category}：{len(items)} 个\n"
                for item in items[:2]:
                    instance = item.get('instance', '未知实例')
                    alert_name = item.get('alert_name', '未知告警')
                    report += f"  - {instance}: {alert_name}\n"
                if len(items) > 2:
                    report += f"  - 及其他 {len(items) - 2} 个相关告警...\n"
            report += "\n"
        
        report += "🚨 **紧急处理建议**\n"
        report += "• 立即检查Prometheus和AlertManager状态\n"
        report += "• 优先处理实例不可达和严重级别告警\n"
        report += "• 检查是否存在网络或基础设施问题\n"
        report += "• 考虑临时调整告警规则，降低噪音\n\n"
        
        report += f"📊 **系统健康度**: 🔴 **严重异常** - 告警风暴状态，需立即介入"
        
        return report
    
    def _builtin_analysis(self, alerts: List[Dict[str, Any]]) -> str:
        """内置分析（当没有AI服务时）"""
        if not alerts:
            return "✅ **系统运行正常**\n\n当前无活跃告警，所有监控目标状态良好。"
        
        stats = self._calculate_statistics(alerts)
        health_status = self._get_health_status(stats)
        
        report = f"📊 **告警概况**：{stats['total']} 个活跃告警，涉及 {stats['instances_count']} 个实例\n\n"
        
        # 告警分类汇总
        alert_categories = self._categorize_alerts(alerts)
        if alert_categories:
            report += "🔍 **告警分类汇总**\n"
            for category, items in alert_categories.items():
                instances_info = self._get_instances_info(items)
                report += f"• {category}：{len(items)} 个 {instances_info}\n"
            report += "\n"
        
        # 严重程度统计
        report += "📈 **严重程度分布**\n"
        for severity in ['emergency', 'critical', 'warning', 'info']:
            if severity in stats['severity_count']:
                count = stats['severity_count'][severity]
                severity_name = self.severity_map.get(severity, severity)
                percentage = round(count / stats['total'] * 100)
                report += f"• {severity_name}: {count} 个 ({percentage}%)\n"
        
        # 重点关注告警
        if stats['critical_alerts']:
            report += f"\n🚨 **高优先级告警** ({len(stats['critical_alerts'])} 个)\n"
            for alert in stats['critical_alerts'][:3]:
                severity_name = self.severity_map.get(alert['severity'], alert['severity'])
                report += f"• [{severity_name}] {alert['instance']}: {alert['alert_name']}\n"
        
        # 系统健康度评估
        report += f"\n🎯 **系统健康度**: {health_status}"
        
        return report
    
    def _calculate_statistics(self, alerts: List[Dict[str, Any]]) -> Dict[str, Any]:
        """计算告警统计信息"""
        total_alerts = len(alerts)
        severity_count = {}
        instances_affected = set()
        critical_alerts = []
        
        for alert in alerts:
            severity = alert.get('severity', 'warning')
            severity_count[severity] = severity_count.get(severity, 0) + 1
            
            instance = alert.get('instance', '未知实例')
            instances_affected.add(instance)
            
            # 严重和紧急级别告警
            if severity in ['critical', 'emergency']:
                critical_alerts.append(alert)
        
        return {
            'total': total_alerts,
            'severity_count': severity_count,
            'instances_count': len(instances_affected),
            'critical_alerts': critical_alerts
        }
    
    def _get_health_status(self, stats: Dict[str, Any]) -> str:
        """计算系统健康度状态"""
        total = stats['total']
        critical_count = len(stats['critical_alerts'])
        
        if critical_count > 0:
            return "🔴 **严重异常** - 存在高风险告警，需立即处理"
        elif total == 0:
            return "🟢 **运行正常** - 所有系统状态良好"
        elif total <= 2:
            return "🟡 **基本正常** - 少量低级别告警，整体可控"
        elif total <= 5:
            return "🟠 **亚健康状态** - 多个低级别异常，建议排查"
        else:
            return "🔴 **异常状态** - 告警数量过多，可能存在系统性问题"